﻿using System;
using System.Diagnostics;
using System.Linq;
using System.Security.Cryptography;
using System.Text;

namespace Microsoft.Coding4Fun.TweetCraft.Tray
{
    public partial class Settings
    {
        private static readonly byte[] Entropy = Encoding.Unicode.GetBytes("TweetCraftSalt");
        private static readonly string[] EncryptedPropertyNames = new[]
                                                                  {
                                                                      "TwitterUserName",
                                                                      "TwitterPassword"
                                                                  };

        public override object this[string propertyName]
        {
            get
            {
                if (EncryptedPropertyNames.Contains(propertyName))
                {
                    object value = base[propertyName];
                    if (value.GetType() != typeof(string))
                        throw new InvalidOperationException(Strings.OnlyStringValuesCanBeStoredEncrypted);

                    return DecryptString((string)base[propertyName]);
                }

                return base[propertyName];
            }
            set
            {
                if (value == null)
                    throw new ArgumentNullException("value");

                if (EncryptedPropertyNames.Contains(propertyName))
                {
                    if (value.GetType() != typeof(string))
                        throw new InvalidOperationException(Strings.OnlyStringValuesCanBeStoredEncrypted);

                    base[propertyName] = EncryptString((string)value);
                }
                else
                    base[propertyName] = value;
            }
        }

        private static string EncryptString(string input)
        {
            byte[] encryptedData = ProtectedData.Protect(Encoding.Unicode.GetBytes(input), Entropy, DataProtectionScope.CurrentUser);
            return Convert.ToBase64String(encryptedData);
        }

        private static string DecryptString(string encryptedData)
        {
            if (String.IsNullOrEmpty(encryptedData))
                return String.Empty;

            try
            {
                byte[] decryptedData = ProtectedData.Unprotect(Convert.FromBase64String(encryptedData), Entropy, DataProtectionScope.CurrentUser);
                return Encoding.Unicode.GetString(decryptedData);
            }
            catch
            {
                // Trace the issue
                Trace.TraceError("Failed to decrypt encrypted setting. EncryptedData: " + encryptedData);

                // We are safe to return String.Empty as we're only losing the value of a setting
                // as a result of a malformed (possibly tampered with) input from user.config
                return String.Empty;
            }
        }
    }
}